// try {
//     eval("var packer3d = require('3d-bin-packing')");
//     eval("var packer2d = require('packer-2d')");
// } catch (e) {
// };

MatchVehicle = function(vehicles, cargo) {
    this.init(vehicles, cargo);
};

MatchVehicle.prototype = {
    init: function(vehicles, cargo) {
        this.vehicles = vehicles;
        this.cargo = cargo;
        for(let i = 0; i < cargo.cargos.length; i++) {
            c = cargo.cargos[i];
            c.volume = (c.length/1000) * (c.width/1000) * (c.height/1000);
        }
    },

    clearResult: function() {
        this.result = null;
        this.vehicle = null;
    },

    filterWeight: function() {
        let delete_size = 0;

        let van_avg_volume = 0.2;   // 卡板单件货物体积上限
        let van_avg_weight = 60;    // 卡板单件货物重量上限
        let single_weight_max = 0;  // 单件货物的最大重量
        for(let i = 0; i < this.cargo.cargos.length; i++) {
            let matchC = this.cargo.cargos[i];

            if (matchC.weight > single_weight_max) {
                single_weight_max = matchC.weight;
            }

            if (delete_size == 0) {
                if(matchC.pallet) {
                    delete_size += 1;
                }
                else if(matchC.volume > van_avg_volume || matchC.weight > van_avg_weight) {
                    this.warning = '货物不方便装卸（总量、体积）.';
                    this.single_weight_advise = this.vehicles[1];   // 根据单件货物重量的建议车型
                }
            }
        }
        this.single_weight_max = single_weight_max;

        let advise_vehicle_max = true;
        for(let i = delete_size; i < this.vehicles.length; i++) {
            let matchV = this.vehicles[i];
            if(this.cargo.volume > matchV.volume || this.cargo.weight > matchV.weight) {
                delete_size += 1;
            }
            if (matchV.single_cargo_weight_max < single_weight_max &&
                (!this.single_weight_advise || matchV.id > this.single_weight_advise.id)) {
                this.single_weight_advise = matchV;         // 根据单件货物重量的建议车型
            }

            if (matchV.single_cargo_weight_max < single_weight_max) {
                if (!this.single_weight_advise || matchV.id > this.single_weight_advise.id) {
                    this.single_weight_advise = matchV;         // 根据单件货物重量的建议车型
                }
                advise_vehicle_max = false;
            } else if (!advise_vehicle_max) {
                advise_vehicle_max = true;
                if(matchV.id > this.single_weight_advise.id) {
                    this.single_weight_advise = matchV;
                }
            }
        }

        // 面包车配车警告
        // if(delete_size == 0) {
        //     let van_avg_volume = 0.2;   // 卡板单件货物体积上限
        //     let van_avg_weight = 60;    // 卡板单件货物重量上限
        //     let single_weight_max = 0;  // 单件货物的最大重量

        //     for(let i = 0; i < this.cargo.cargos.length; i++) {
        //         let matchC = this.cargo.cargos[i];

        //         if (matchC.weight > single_weight_max) {
        //             single_weight_max = matchC.weight;
        //         }

        //         if(matchC.pallet) {
        //             delete_size += 1;
        //             break
        //         }
        //         else if(matchC.volume > van_avg_volume || matchC.weight > van_avg_weight) {
        //             this.warning = '货物不方便装卸（总量、体积）.';
        //             break;
        //         }
        //     }
        // }


        this.vehicles.splice(0, delete_size);
        return this.vehicles;
    },

    reportResult: function() {
        if (this.vehicle) {
            this.result = {
                errCode: 0,
                errInfo: 'success',
                vehicle: {
                    id: this.vehicle.id,
                    name: this.vehicle.name,
                    utilization: this.cargo.volume / this.vehicle.volume
                }
            };

            if (this.warning)
                this.result.warning = this.warning;

            // 单件货物重量超标
            if (this.single_weight_advise && this.single_weight_advise.id > this.vehicle.id) {
                this.result.warning = '货物不方便装卸（总量、体积）.';
                this.result.vehicle = {
                    id: this.single_weight_advise.id,
                    name: this.single_weight_advise.name,
                    utilization: this.cargo.volume / this.single_weight_advise.volume
                };
            }
        } else {
            this.result = {
                errCode: 1,
                errInfo: '没有匹配的车型'
            }
        }
        return this.result;
    },

    match: function() {
        this.clearResult();
        this.filterWeight();
        if (this.cargo.cargos.length == 0) {    // 没有货物明细
            this.packerNoCargos();
        } else if (!this.cargo.pallet) {        // 没有卡板
            this.packer3d();
        } else if (!this.cargo.rotatable && !this.cargo.stackable) {     // 货物不可旋转、不可堆叠
            this.packer2d();
        } else if (!this.cargo.rotatable && this.cargo.stackable) {     // 货物不可旋转、可堆叠
            this.packerPalletStackNoRotate();
        } else if (this.cargo.rotatable && !this.cargo.stackable) {     // 货物可旋转、不可堆叠
            this.packerPalletRotate();
        } else {                                // 货物可旋转、可堆叠
            this.packerPalletRotateStack();
        }
        return this.reportResult();
    },

    limitUtilization: function(pcbm_count) {
        let utilization = 0;
        if (pcbm_count > 100) {
            utilization = 0.9;
        } else if (pcbm_count > 5) {
            utilization = 0.8;
        } else {
            utilization = 0.7;
        }
        return utilization;
    },

    // 没有货物明细时的配车算法
    packerNoCargos: function() {
        pcbm_count = this.cargo.count / this.cargo.volume;
        let utilization = this.limitUtilization(pcbm_count);

        for(let i = 0; i < this.vehicles.length; i++) {
            vehicle = this.vehicles[i];
            if (vehicle.volume * utilization >= this.cargo.volume) {
                this.vehicle = vehicle;
                return true;
            }
        }
        return false;
    },

    // 3D装箱算法
    // 前提条件：
    //      1. 可旋转
    //      2. 可堆叠
    // 车厢预留情况：
    //      1. 车长预留50mm
    //      3. 车宽预留0mm
    //      2. 车高预留100mm
    // 使用场景：
    //      1. 非卡板类货物
    packer3d: function() {
        let space_lenght = 50;
        let space_width = 0;
        let space_height = 100;

        let instanceArray = new bws.packer.InstanceArray();
        for(let i = 0, len = this.cargo.cargos.length; i < len; i++){
            let cargo = this.cargo.cargos[i];
            instanceArray.insert(instanceArray.end()
                , cargo.count
                , new bws.packer.Product(cargo.package, cargo.width, cargo.height, cargo.length)
            );
        }

        let wrapperArray = null;
        for(let i = 0, len = this.vehicles.length; i < len; i++){
            let matchV = this.vehicles[i];

            wrapperArray = new bws.packer.WrapperArray();
            wrapperArray.push(new bws.packer.Wrapper(matchV.name, 0, matchV.width - space_width, matchV.height - space_height, matchV.length - space_lenght, 0));

            let result = (new bws.packer.Packer(wrapperArray, instanceArray)).optimize();
            if(!result.error && (1 === result.data_.length)){
                this.vehicle = matchV;
                return true;
            }
        }
        return false;
    },

    // 3D装箱算法（卡板、可旋转、可堆叠）
    // 前提条件：
    //      1. 只可横竖旋转（垂直Z轴方向）
    //      2. 可堆叠
    //      3. 每件货物只能由一件货物托住
    // 车厢预留情况：
    //      1. 车长预留50mm
    //      3. 车宽预留50mm
    //      2. 车高预留100mm
    // 使用场景：
    //      1. 卡板类货物，可旋转、可堆叠
    packerPalletRotateStack: function() {
        let height_rate = 10000.0;
        let wrapperArray = null;
        let instanceArray = new bws.packer.InstanceArray();

        let space_lenght = 50;
        let space_width = 50;
        let space_height = 100;

        for(let i = 0, len = this.cargo.cargos.length; i < len; i++){
            let cargo = this.cargo.cargos[i];
            instanceArray.insert(instanceArray.end()
                , cargo.count
                , new bws.packer.Product(cargo.name, cargo.width, cargo.height * height_rate, cargo.length)
            );
        }
        for(let i = 0, len = this.vehicles.length; i < len; i++){
            let matchV = this.vehicles[i];

            wrapperArray = new bws.packer.WrapperArray();
            wrapperArray.push(new bws.packer.Wrapper(matchV.name, 0, matchV.width - space_width, (matchV.height - space_height) * height_rate, matchV.length - space_lenght, 0));

            let result = (new bws.packer.Packer(wrapperArray, instanceArray)).optimize();

            if(!result.error && (1 === result.data_.length)){
                this.vehicle = matchV;
                return true;
            }
        }

        return false;
    },

    // 3D装箱算法（卡板、可旋转、不可堆叠）
    // 前提条件：
    //      1. 只可横竖旋转（垂直Z轴方向）
    //      2. 可堆叠
    //      3. 每件货物只能由一件货物托住
    // 车厢预留情况：
    //      1. 车长预留50mm
    //      3. 车宽预留50mm
    //      2. 车高预留100mm
    // 使用场景：
    //      1. 卡板类货物，可旋转、不可堆叠
    packerPalletRotate: function() {
        let wrapperArray = null;
        let instanceArray = new bws.packer.InstanceArray();

        let space_lenght = 50;
        let space_width = 50;
        let space_height = 100;
        let max_cargo_height = 0;

        for(let i = 0, len = this.cargo.cargos.length; i < len; i++){
            let cargo = this.cargo.cargos[i];
            instanceArray.insert(instanceArray.end(),
                cargo.count,
                new bws.packer.Product(cargo.name, cargo.width, 1, cargo.length)
            );

            if (max_cargo_height < cargo.height) {
                max_cargo_height = cargo.height;
            }
        }
        for(let i = 0, len = this.vehicles.length; i < len; i++){
            let matchV = this.vehicles[i];

            if (max_cargo_height > matchV.height - space_height) {
                continue;
            }

            wrapperArray = new bws.packer.WrapperArray();
            wrapperArray.push(new bws.packer.Wrapper(matchV.name, 0, matchV.width - space_width, 1, matchV.length - space_lenght, 0));

            let result = (new bws.packer.Packer(wrapperArray, instanceArray)).optimize();

            if(!result.error && (1 === result.data_.length)){
                this.vehicle = matchV;
                return true
            }
        }

        return false;
    },

    // 3D装箱算法（卡板、不可旋转、可堆叠）
    // 前提条件：
    //      1. 不可旋转
    //      2. 可堆叠
    //      3. 每件货物只能由一件货物托住
    // 车厢预留情况：
    //      1. 车长预留50mm
    //      3. 车宽预留50mm
    //      2. 车高预留100mm
    // 使用场景：
    //      1. 卡板类货物，不可旋转、可堆叠
    packerPalletStackNoRotate: function() {
        let packer = null;

        let space_lenght = 50;
        let space_width = 50;
        let space_height = 100;

        blocks = []
        for(let i = 0, len = this.cargo.cargos.length; i < len; i++){
            let cargo = this.cargo.cargos[i];

            for(let j = 0, ilen = cargo.count; j < ilen; j++){
                blocks.push({length: cargo.width, width: cargo.length, height: cargo.height, used: false});
            }
        }

        for(let i = 0, len = this.vehicles.length; i < len; i++){
            let matchV = this.vehicles[i];

            packer = new Packer3DStackNoRotate(matchV.length - space_lenght, matchV.width - space_width, matchV.height - space_height);
            let result = packer.packer(blocks);

            if(result){
                this.vehicle = matchV;
                return true;
            }
        }

        return false;
    },

    // 2D装箱算法（卡板）
    // 前提条件：
    //      1. 不可旋转
    //      2. 不可堆叠
    // 车厢预留情况：
    //      1. 车长预留50mm
    //      3. 车宽预留50mm
    //      2. 车高预留100mm
    // 使用场景：
    //      1. 卡板类货物，不可旋转、不可堆叠
    // 备注：
    //      1. 卡板使用2D装箱算法
    //      2. 普通货物按照百分比摆放
    packer2d: function() {
        let blocks = [];

        let space_lenght = 50;
        let space_width = 50;
        let space_height = 100;

        let max_height = 0, max_eara = 0;
        let all_count = 0, other_count = 0, other_volume = 0, pallet_volume = 0;

        let cargos = this.cargo.cargos;
        for(let i = 0, len = cargos.length; i < len; i++){
            let cargo = cargos[i];
            all_count += cargo.count;

            if(!cargo.pallet) {
                other_count += cargo.count;
                other_volume += cargo.volume * cargo.count;
                continue;
            }

            pallet_volume += cargo.volume * cargo.count;
            max_eara += cargo.width * cargo.length * cargo.count;
            if(cargo.height > max_height) {
                max_height = cargo.height;
            }
            for(let j = 0, ilen = cargo.count; j < ilen; j++){
                blocks.push({w: cargo.width, h: cargo.length});
            }
        }

        // 摆放其他货物需要的空间
        let max_volume = pallet_volume;
        if (other_count > 0) {
            let utilization = limitUtilization(other_count / other_volume)
            max_volume = other_volume / utilization;
        }

        // 货物排序
        if(blocks.length) {
            blocks.sort((a, b) => {
                return (a.h < b.h || (a.h == b.h && a.w < b.w))
            });
        }

        let packer = null;
        for(let i = 0, len = this.vehicles.length; i < len; i++) {
            let matchV = this.vehicles[i];

            let vehicle_eare = (matchV.width - space_width) * (matchV.length - space_lenght);
            let vehicle_volume = (vehicle_eare / 1000000) * (matchV.height - space_height) / 1000;
            if (max_volume > vehicle_volume) {
                continue;
            }

            if(max_height > (matchV.height - space_height) || max_eara > vehicle_eare) {
                continue;
            }

            packer = new Packer2D(matchV.width, matchV.length);
            let result = packer.fit(blocks);
            if(result.data.length === blocks.length) {
                this.vehicle = matchV;
                return true;
            }
        }
        return false;
    },
}
